const config = require('../config/config')

class Request {
  constructor() {
    this.baseURL = config.baseURL
    this.timeout = 10000
    this.isRefreshing = false // 防止重复刷新
    this.requestQueue = [] // 等待刷新的请求队列
  }

  // 1. 获取本地存储的令牌（适配你的存储格式）
  getAccessToken() {
    return wx.getStorageSync('token') || '';
  }
  getRefreshToken() {
    return wx.getStorageSync('refreshToken') || '';
  }
  getExpiresTime() {
    return wx.getStorageSync('expiresTime') || 0; // 过期时间戳（accessToken的过期时间）
  }

  // 2. 更新本地令牌（登录/刷新成功后调用）
  updateTokens(newToken, newRefreshToken, newExpiresTime) {
    wx.setStorageSync('token', newToken);
    wx.setStorageSync('refreshToken', newRefreshToken);
    wx.setStorageSync('expiresTime', newExpiresTime);
  }

  // 3. 清除本地令牌
  clearTokens() {
    wx.removeStorageSync('token');
    wx.removeStorageSync('refreshToken');
    wx.removeStorageSync('expiresTime');
  }

  // 4. 判断accessToken是否即将过期（提前5分钟刷新）
  isAccessTokenExpiring() {
    const expiresTime = this.getExpiresTime();
    if (!expiresTime) return true; // 无过期时间视为过期
    const now = Date.now();
    return expiresTime - now < 5 * 60 * 1000; // 剩余时间 < 5分钟
  }

  // 5. 请求拦截器：添加accessToken
  requestInterceptor(requestConfig) {
    // 登录接口不添加token
    if (requestConfig.url.includes('/mini-login')) {
      // 仅添加公共参数，不添加Authorization
      requestConfig.header['Content-Type'] = 'application/json';
      requestConfig.header['X-Client-Type'] = 'mini-program';
      return requestConfig;
    }
    const accessToken = this.getAccessToken();
    if (accessToken) {
      requestConfig.header['Authorization'] = `Bearer ${accessToken}`;
    }
    // 公共参数
    requestConfig.header['Content-Type'] = 'application/json';
    requestConfig.header['X-Client-Type'] = 'mini-program';
    // 开发环境日志
    if (config.debug) {
      console.log('🚀 请求参数:', requestConfig);
    }
    return requestConfig;
  }

  // 6. 响应拦截器：处理业务码
  responseInterceptor(response) {
    const {
      data,
      statusCode
    } = response;

    if (config.debug) {
      console.log('✅ 响应数据:', data);
      console.log("状态码：", statusCode);
    }

    if (statusCode === 200) {
      // 业务码401：accessToken过期
      if (data.code === 401) {
        const error = new Error('accessToken expired');
        error.statusCode = 401;
        throw error;
      } else if (data.code === 400) {
        wx.showModal({
          title: '提示',
          content: data.msg,
          confirmText: '确认',
          showCancel: false
        });
      } else if (data.code === 500) {
        wx.showModal({
          title: '提示',
          content: '系统错误',
          confirmText: '确认',
          showCancel: false
        });
      } else if (data.code === 403) {
        wx.showModal({
          title: '提示',
          content: '没有该操作权限',
          confirmText: '确认',
          showCancel: false
        });
      }
      return data;
    } else {
      throw response;
    }
  }

  // 7. 调用后端刷新令牌接口
  async refreshToken() {
    const refreshToken = this.getRefreshToken();
    if (!refreshToken) {
      throw new Error('无refreshToken');
    }
    try {
      // 调用后端刷新接口（仅传递refreshToken）
      const res = await new Promise((resolve, reject) => {
        wx.request({
          url: `${this.baseURL}/admin-api/system/auth/refresh-token`, // 后端刷新接口地址
          method: 'GET',
          data: {
            "refreshToken": refreshToken
          }, // 传递refreshToken
          header: {
            'Content-Type': 'application/json',
            'X-Client-Type': 'mini-program'
          },
          success: resolve,
          fail: reject
        });
      });

      // 假设后端返回格式：{ code:0, data: { accessToken, refreshToken, expiresTime } }
      if (res.statusCode === 200 && res.data.code === 0) {
        const {
          accessToken,
          refreshToken,
          expiresTime
        } = res.data.data;
        this.updateTokens(accessToken, refreshToken, expiresTime); // 更新本地存储
        return true;
      } else {
        throw new Error('refreshToken无效或已过期');
      }
    } catch (error) {
      throw error;
    }
  }

  // 8. 错误处理：核心刷新逻辑
  async handleError(error) {
    if (config.debug) {
      console.error('❌ 请求错误:', error);
    }

    const statusCode = error.statusCode || error.errno;


    // 处理401错误（accessToken过期）
    if (statusCode === 401) {
      try {
        // 若正在刷新，将请求加入队列等待
        if (this.isRefreshing) {
          return new Promise((resolve) => {
            this.requestQueue.push(resolve);
          }).then(() => {
            // 刷新完成后重试原请求

            return this.request(error.config);
          });
        }

        this.isRefreshing = true; // 标记正在刷新

        // 调用刷新接口
        await this.refreshToken();

        // 重试队列中的所有请求
        this.requestQueue.forEach(resolve => resolve());
        this.requestQueue = [];

        // 重试当前请求
        return this.request(error.config);
      } catch (refreshError) {
        // 刷新失败（refreshToken过期），跳转登录
        this.clearTokens();
        wx.showModal({
          title: '提示',
          content: '登录已过期，请重新登录',
          confirmText: '重新登录',
          cancelText: '取消',
          success: (res) => {
            if (res.confirm) {
              wx.reLaunch({
                url: '/pages/index/index'
              });
            }
          }
        });
        return Promise.reject(refreshError);
      } finally {
        this.isRefreshing = false; // 重置刷新状态
      }
    }

    // 其他错误处理
    let message = '网络请求失败';
    switch (statusCode) {
      case 403:
        message = '无访问权限';
        break;
      case 500:
        message = '服务器错误';
        break;
      default:
        message = error.data?.msg || error.errMsg || '网络请求失败';
    }

    wx.showToast({
      title: message,
      icon: 'none',
      duration: 2000
    });
    return Promise.reject(error);
  }

  // 9. 通用请求方法
  request(options) {
    const {
      url,
      method = 'GET',
      data = {},
      header = {}
    } = options;
    let newUrl;
    if (url.startsWith(this.baseURL)) {
      newUrl = url;
    } else {
      newUrl = `${this.baseURL}${url}`
    }
    // 构建请求配置（包含原始参数用于重试）
    const requestConfig = {
      url: newUrl,
      method,
      data,
      header,
      timeout: this.timeout,
      originalOptions: {
        ...options,
        url
      }
    };



    // 执行请求拦截器
    const finalConfig = this.requestInterceptor(requestConfig);

    return new Promise((resolve, reject) => {
      // 提前检查令牌是否即将过期（排除刷新接口本身）
      if (finalConfig.url.includes('/mini-login') || finalConfig.url.includes('/refresh-token')) {} else {
        if (this.isAccessTokenExpiring()) {
          this.handleError({
              statusCode: 401,
              config: finalConfig
            })
            .then(resolve)
            .catch(reject);
          return;
        }
      }


      // 发起请求
      wx.request({
        ...finalConfig,
        success: (res) => {
          try {
            const result = this.responseInterceptor(res);
            resolve(result);
          } catch (error) {
            error.config = finalConfig; // 传递配置供重试
            this.handleError(error).then(resolve).catch(reject);
          }
        },
        fail: (error) => {
          error.config = finalConfig;
          this.handleError(error).catch(reject);
        }
      });
    });
  }

  // 10. 快捷方法（保持不变）
  get(url, data = {}) {
    return this.request({
      url,
      method: 'GET',
      data
    });
  }

  post(url, data = {}) {
    return this.request({
      url,
      method: 'POST',
      data
    });
  }

  put(url, data = {}) {
    return this.request({
      url,
      method: 'PUT',
      data
    });
  }

  delete(url, data = {}) {
    return this.request({
      url,
      method: 'DELETE',
      data
    });
  }

  // 11. 上传文件方法（适配令牌刷新）
  upload(url, filePath, formData = {}) {
    return new Promise((resolve, reject) => {
      const accessToken = this.getAccessToken();

      // 检查令牌是否即将过期
      if (this.isAccessTokenExpiring()) {
        this.handleError({
          statusCode: 401,
          config: {
            url,
            method: 'UPLOAD',
            data: formData
          }
        }).then(() => {
          // 刷新后重新上传
          const newToken = this.getAccessToken();
          this.uploadFile(url, filePath, formData, newToken).then(resolve).catch(reject);
        }).catch(reject);
        return;
      }

      // 直接上传
      this.uploadFile(url, filePath, formData, accessToken).then(resolve).catch(reject);
    });
  }

  // 封装上传文件的实际逻辑
  uploadFile(url, filePath, formData, token) {
    return new Promise((resolve, reject) => {
      wx.uploadFile({
        url: `${this.baseURL}${url}`,
        filePath: filePath,
        name: 'file',
        formData: formData,
        header: {
          'Authorization': `Bearer ${token}`
        },
        success: (res) => {
          const data = JSON.parse(res.data);
          if (data.code === 401) {
            // 上传时token过期，触发刷新
            this.handleError({
              statusCode: 401,
              config: {
                url,
                method: 'UPLOAD',
                data: formData
              }
            }).then(() => {
              const newToken = this.getAccessToken();
              this.uploadFile(url, filePath, formData, newToken).then(resolve).catch(reject);
            }).catch(reject);
          } else {
            resolve(data);
          }
        },
        fail: (error) => {
          this.handleError(error).catch(reject);
        }
      });
    });
  }
}

module.exports = new Request()